Skip to content

BT-6886: fix: label unhandled promise rejections as 'Unhandled rejection'#370

Open
GT1990 wants to merge 2 commits into
mainfrom
aibrahim/BT-6886/unhandled-rejection-label
Open

BT-6886: fix: label unhandled promise rejections as 'Unhandled rejection'#370
GT1990 wants to merge 2 commits into
mainfrom
aibrahim/BT-6886/unhandled-rejection-label

Conversation

@GT1990
Copy link
Copy Markdown
Contributor

@GT1990 GT1990 commented May 13, 2026

Summary

Issue was customer was getting failed-fetch promise rejections labeled as unhandled exceptions. They created a support request to figure out if they were actually exceptions or if our sdk reclassifies them as an exception.

After some digging turns out their error was a UnhandledPromiseRejection and our sdk was reclassifying it as a unhandled exception.

task: BT-6886

what changed

  • added 'Unhandled rejection' to BacktraceErrorType
  • async paths (unhandledrejection in browser, unhandledRejection in node, promise rejection tracker in react-native) now stamp error.type: 'Unhandled rejection'
  • sync paths (error, uncaughtException, error boundaries, android native) still stamp error.type: 'Unhandled exception'
  • regression tests added per sdk

…promise rejections as 'Unhandled rejection'

Adds 'Unhandled rejection' to BacktraceErrorType and uses it on the
async error paths in browser, node, and react-native SDKs. Sync paths
(window 'error' event, uncaughtException, RN ErrorBoundary, Android
native) keep 'Unhandled exception'.

Unhandled promise rejections and synchronous unhandled exceptions are
distinct browser/node events with different crash semantics, but the
JS SDKs were stamping both with error.type 'Unhandled exception'. The
'UnhandledPromiseRejection' classifier already captured the truth; the
attribute now matches it. Customers can filter sync crashes from async
noise without union queries.

Verified end-to-end against a real Backtrace endpoint: async path
submits with error.type 'Unhandled rejection', sync path still
submits with 'Unhandled exception'.
Copy link
Copy Markdown
Contributor

@melekr melekr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@@ -0,0 +1,60 @@
import { BacktraceRequestHandler } from '@backtrace/sdk-core';
import { BacktraceClient } from '../../src/index.js';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a regression test for the direct unhandledRejection handler path as well?

test something like :

Suggested change
expect(payload.attributes['error.type']).toBe('Unhandled rejection');
expect(payload.classifiers).toContain('UnhandledPromiseRejection');

const rejectionTracking = require('promise/setimmediate/rejection-tracking');

import { UnhandledExceptionHandler } from '../src/handlers/UnhandledExceptionHandler';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a great addition.

Could we add a Hermes path test here as well?

…stener + Hermes path

Addresses review feedback on PR #370:
- node: new test exercises the dedicated process.prependListener('unhandledRejection', ...) path that runs under --unhandled-rejections=warn / Node 14. Was previously only covered via the shared uncaughtExceptionMonitor callback.
- react-native: new test exercises the Hermes branch in captureUnhandledPromiseRejections by mocking hermes() to return a HermesInternal-shaped object with hasPromise and enablePromiseRejectionTracker. Was previously only covered via the non-Hermes rejectionTracking.enable path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants